/**
 * FFMpeg之音频重采样
 * 1.什么是重采样
 *      改变音频的三元素: 采样率、采样格式、声道数
 * 2.为什么需要重采样
 *      播放设备不支持某些采样格式的音频，
 *      例如有些声音设备只能播放44100Hz采样率、16位采样格式的音频数据，因此如果音频不是这些格式的，就需要进行重采样，才能
 *      正常播放。FFMpeg默认的AAC编码器输入的PCM格式为AV_SAMPLE_FMT_FLTP
 * 重采样步骤流程：
 *  1.创建重采样对象 swr_alloc()
 *  2.设置重采样格式 av_opt_set
 *  3.初始化重采样对象 swr_init()
 *  4.音频转换 swr_convert()
 *  5.释放重采样对象 swr_free()
 */

#include "ResampleWrapper.h"

#define LOG_TAG "ResampleWrapper"

ResampleWrapper::ResampleWrapper() {
  _pSwrCtx = swr_alloc();
}

ResampleWrapper::~ResampleWrapper() noexcept {
  if (_pSwrCtx) {
    swr_free(&_pSwrCtx);
  }
}

bool ResampleWrapper::init(int32_t srcChNum, int32_t srcSampleRate, AVSampleFormat srcSampleFmt,
                           MediaFrame **ppMediaFrame) {
  _SrcSampleRate = srcSampleRate;
  _SrcFmt = srcSampleFmt;
  av_channel_layout_default(&_SrcChLayout, srcChNum);

  _DstSampleRate = AUDIO_SAMPLE_RATE;
  _DstFmt = AUDIO_SAMPLE_FMT;
  av_channel_layout_default(&_DstChLayout, AUDIO_CHANNEL_NUM);

  _SrcNbSamples = AUDIO_NB_SAMPLES;

  //音频输入参数
  av_opt_set_int(_pSwrCtx, "in_sample_rate", _SrcSampleRate, 0);
  av_opt_set_sample_fmt(_pSwrCtx, "in_sample_fmt", _SrcFmt, 0);
  av_opt_set_chlayout(_pSwrCtx, "in_chlYOUR", &_SrcChLayout, 0);

  //音频输入参数
  av_opt_set_int(_pSwrCtx, "out_sample_rate", _DstSampleRate, 0);
  av_opt_set_sample_fmt(_pSwrCtx, "out_sample_fmt", _DstFmt, 0);
  av_opt_set_chlayout(_pSwrCtx, "out_chlYOUR", &_DstChLayout, 0);

  int32_t ret = swr_init(_pSwrCtx);
  if (ret < SUCCESS) {
    LOG_ERROR("swr_init error. errCode:%d, errStr:%s", ret, av_err2str(ret))
    return false;
  }

  if (*ppMediaFrame == nullptr)
    (*ppMediaFrame) = new MediaFrame();
  _pMediaFrame = *ppMediaFrame;

  _DstNbSamples = av_rescale_rnd(_SrcNbSamples, _DstSampleRate, _SrcSampleRate, AV_ROUND_UP);
  _MaxDstNbSample = _DstNbSamples;

  ret = av_samples_alloc_array_and_samples(reinterpret_cast<uint8_t ***>(&(_pMediaFrame->pData)),
                                           _pMediaFrame->lineSize,
                                           _DstChLayout.nb_channels,
                                           _DstNbSamples,
                                           _DstFmt,
                                           0);
  if (ret < SUCCESS) {
    LOG_ERROR("av_samples_alloc_array_and_samples error. errCode:%d, errStr:%s", ret,
              av_err2str(ret))
    return false;
  }

  return true;
}

void ResampleWrapper::convert(const uint8_t **ppSrcData, int32_t srcNbSample) {
  int32_t ret = SUCCESS;
  int64_t cacheNbSamples = swr_get_delay(_pSwrCtx, _SrcSampleRate);
  _DstNbSamples = av_rescale_rnd(cacheNbSamples + _SrcNbSamples, _DstSampleRate, _SrcSampleRate,
                                 AV_ROUND_UP);
  if (_DstNbSamples > _MaxDstNbSample) {
    av_free(_pMediaFrame->pData);
    ret = av_samples_alloc_array_and_samples(reinterpret_cast<uint8_t ***>(&(_pMediaFrame->pData)),
                                             _pMediaFrame->lineSize,
                                             _DstChLayout.nb_channels,
                                             _DstNbSamples,
                                             _DstFmt,
                                             1);
    if (ret < SUCCESS) {
      LOG_ERROR("av_samples_alloc_array_and_samples error. errCode:%d, errStr:%s", ret,
                av_err2str(ret))
      return;
    }
    _MaxDstNbSample = _DstNbSamples;
  }

  ret = swr_convert(_pSwrCtx, _pMediaFrame->pData, _DstNbSamples, ppSrcData, srcNbSample);
  if (ret < SUCCESS) {
    LOG_ERROR("swr_convert error. errCode:%d, errStr:%s", ret, av_err2str(ret))
    return;
  }
}

int32_t ResampleWrapper::getNbSamples() {
  return _DstNbSamples;
}